package io.renren.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import io.renren.common.exception.RRException;
import io.renren.common.utils.*;
import io.renren.common.validator.ValidatorUtils;
import io.renren.entity.*;
import io.renren.group.UpdateGroup;
import io.renren.param.SeatApplicationSaveParam;
import io.renren.param.SeatBindStatus;
import io.renren.param.SeatSaveParam;
import io.renren.param.SeatUpdateParam;
import io.renren.service.*;
import io.renren.vo.SeatVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.math.BigInteger;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * 工位
 *
 * @author 1
 * @email 1@2.com
 * @date 2021-11-19 11:03:23
 */
@RestController
@RequestMapping("/seat")
@Slf4j
public class SeatController {
    @Autowired
    private SeatService seatService;
    @Autowired
    private SeatEslService seatEslService;
    @Autowired
    private EslService eslService;
    @Autowired
    private EslWorkingService eslWorkingService;
    @Autowired
    private ApService apService;
    @Autowired
    private SeatApplicationService seatApplicationService;
    @Autowired
    private RoomEslService roomEslService;
    @Autowired
    private RoomService roomService;
    @Autowired
    private EslContentService eslContentService;

    /**
     * 列表
     */
    @RequestMapping("/list")
    public R list(@RequestParam Map<String, Object> params) {

        if ((String) params.get("bookDate") != null) {

            Date bookDate = Convert.toDate((String) params.get("bookDate"));
            if (DateUtil.between(bookDate, new Date(), DateUnit.DAY) > 7) {
                return R.error("只能预定7天以内的工位");
            }
        }

        if (StringUtils.isBlank(((String) params.get("city"))) || StringUtils.isBlank((String) params.get("floor"))) {
            return R.ok().put("page", new PageUtils(null, 1, 1, 1));
        }

        SeatPageUtils page = seatService.queryPage(params);
        return R.ok().put("page", page);
    }


    /**
     * 信息
     */
    @RequestMapping("/info/{compId}/{id}")
    public R info(@PathVariable("compId") String compId, @PathVariable("id") String id) {
        SeatVo seatVo = seatService.queryByCodeAndCompId(id, compId);

        return R.ok().put("seat", seatVo);
    }

    /**
     * 保存
     */
    @RequestMapping("/save")
    @Transactional
    public R save(@RequestBody SeatSaveParam param) {
        ValidatorUtils.validateEntity(param);

        param.setEslId(IntDexUtils.DtoH(new BigInteger(param.getEslId())));

        SeatVo seatVo = seatService.queryByCodeAndCompId(param.getCode(), param.getCompId());
        if (seatVo != null && seatVo.getId() != null) {
            log.info("公司{}已有编码相同的工位{}", param.getCompId(), param.getCode());
            throw new RRException("工位编码重复");
        }

        //查价签是否存在
        EslEntity eslEntity = eslService.queryByEslId(param.getEslId());
        if (eslEntity == null || eslEntity.getEslId() == null) {
            throw new RRException("根据" + param.getEslId() + "找不到对应的铭牌");
        }
        //查价签是否补绑定过
        RoomEslEntity roomEslEntity = roomEslService.queryByEslId(param.getEslId());
        if (roomEslEntity != null) {
            RoomEntity roomEntity = roomService.getById(roomEslEntity.getRoomId());
            throw new RRException("已被会议室[" + roomEntity.getName() + "]绑定");
        }
        SeatEslEntity seatEslEntity = seatEslService.queryByEslId(param.getEslId());
        if (seatEslEntity != null) {
            SeatEntity seaEntity = seatService.getById(seatEslEntity.getSeatId());
            throw new RRException("铭牌已被工位[" + seaEntity.getCode() + "]绑定");
        }

        SeatEntity seatEntity = SeatSaveParam.convertFor(param);
        final String apId = param.getApId();
        if (StringUtils.isNotBlank(apId)) {
            ApEntity apEntity = apService.queryByApId(apId);
            Boolean bindResult = eslWorkingService.bindAp(param.getCompId(), apEntity.getMac());
            if (!bindResult) {
                return R.error("绑定基站失败，请联系管理员");
            }
            seatEntity.setApMac(apEntity.getMac());
        }
        seatService.save(seatEntity);

        //获取seaId
        Long seatId = seatEntity.getId();

        //保存工位价签
        SeatEslEntity newSeatEslEntity = SeatEslEntity.convertFor(String.valueOf(seatId),
                param.getEslId(), param.getType(), param.getCode());
        seatEslService.saveOrUpdate(newSeatEslEntity);

        //更新价签所属用户
        eslEntity.setUser(param.getCompId());
        eslService.saveOrUpdate(eslEntity);

        if ("fixed".equals(param.getType())) {
            SeatApplicationSaveParam applicationSaveParam = new SeatApplicationSaveParam();
            BeanUtil.copyProperties(param, applicationSaveParam);
            applicationSaveParam.setEmployeeName(param.getName());
            SeatApplicationEntity seatApplicationEntity = new SeatApplicationEntity();
            //固定工位，保存一条长期的预约记录，等定时器刷新
            seatApplicationEntity = SeatApplicationEntity.convertForFixedSeat(applicationSaveParam);
            seatApplicationEntity.setSeatId(seatId);
            seatApplicationService.save(seatApplicationEntity);
        }


        return R.ok();
    }

    /**
     * 修改
     */
    @RequestMapping("/update")
    @Transactional(rollbackFor = Exception.class)
    public R update(@RequestBody SeatUpdateParam param) {
        ValidatorUtils.validateEntity(param, UpdateGroup.class);

        log.debug("updating seat info: {}", param);
        final Long seatId = param.getId();
        if (null == seatId) {
            return R.error("待更新的工位ID不能为空");
        }

        final SeatEntity targetSeat = seatService.getById(seatId);
        if (null == targetSeat) {
            return R.error("待更新的工位不存在");
        }

        /* 已经绑定了员工 */
        boolean hasBindEmployee = StringUtils.isNotBlank(targetSeat.getUserId());
        if (!hasBindEmployee && param.isNormalUser()) {
            return R.error("该工位还没有绑定员工，不能修改信息");
        } else {
            if (param.isNormalUser()) {
                if (!StringUtils.equalsIgnoreCase(targetSeat.getUserId(), param.getUserId())) {
                    return R.error("只能修改自己的工位信息");
                }
            }
        }

        final String oldSeatCode = targetSeat.getCode();
        final String originalEslId = param.getEslId();
        param.setEslId(IntDexUtils.DtoH(new BigInteger(originalEslId)));
        final String newEslId = param.getEslId();

        final String newSeatCode = param.getCode();
        boolean seatCodeChanged = !StringUtils.equalsIgnoreCase(oldSeatCode, newSeatCode);

        if (seatCodeChanged) {
            SeatVo existedSeatVo = seatService.queryByCodeAndCompId(newSeatCode, param.getCompId());
            if (null != existedSeatVo) {
                log.info("公司{}已有编码相同的工位{}", param.getCompId(), newSeatCode);
                return R.error("工位编码重复");
            }
        }

        //查价签是否存在
        EslEntity eslEntity = eslService.queryByEslId(param.getEslId());
        if (eslEntity == null || StringUtils.isBlank(eslEntity.getEslId())) {
            return R.error("根据" + newEslId + "找不到对应的铭牌");
        }

        //查价签是否补绑定过
        RoomEslEntity roomEslEntity = roomEslService.queryByEslId(newEslId);
        if (roomEslEntity != null) {
            RoomEntity roomEntity = roomService.getById(roomEslEntity.getRoomId());
            return R.error("已被会议室[" + roomEntity.getName() + "]绑定");
        }

        final SeatEslEntity seatEslEntityInfo = seatEslService.queryBySeatId(seatId);
        boolean eslIdChanged = false;
        if (null != seatEslEntityInfo) {
            final String oldEslId = seatEslEntityInfo.getEslId();
            if (StringUtils.isNotBlank(oldEslId)) {
                eslIdChanged = !StringUtils.equalsIgnoreCase(oldEslId, newEslId);

                if (eslIdChanged) {
                    SeatEslEntity seatEslEntity = seatEslService.queryByEslId(newEslId);
                    if (seatEslEntity != null) {
                        SeatEntity seaEntity = seatService.getById(seatEslEntity.getSeatId());
                        return R.error("铭牌已被工位[" + seaEntity.getCode() + "]绑定");
                    }
                }
            }
        }

        final SeatEntity newSeatEntity = SeatUpdateParam.convertFor(param);

        final String newApMac = param.getApId();
        ApEntity newApEntity = apService.queryByApMac(newApMac);
        if (null == newApEntity) {
            return R.error("无效的基站地址: " + newApMac);
        }
        final String oldApMac = targetSeat.getApMac();

        log.debug("new newApId: {}, old oldApId: {}", newApMac, oldApMac);
        final boolean apMacChanged = !StringUtils.equalsIgnoreCase(newApMac, oldApMac);
        if (apMacChanged) {
            boolean bindApResult = false;
            try {
                bindApResult = eslWorkingService.bindAp(param.getCompId(), newApEntity.getMac());

                newSeatEntity.setApMac(newApEntity.getMac());
            } finally {
                if (bindApResult && StringUtils.isNotBlank(oldApMac)) {
                    eslWorkingService.unBindAp(param.getCompId(), oldApMac);
                }
            }
            if (!bindApResult) {
                return R.error("绑定基站失败，请联系管理员");
            }
        }

        final boolean updateResult = seatService.updateById(newSeatEntity);
        log.debug("seat entity updated result: {}", updateResult);

        SeatEslEntity newSeatEslEntity = SeatEslEntity.convertFor(String.valueOf(seatId),
                newEslId, param.getType(), newSeatCode);
        if (eslIdChanged) {
            //保存工位价签
            seatEslService.updateById(newSeatEslEntity);

            //更新价签所属用户
            eslEntity.setUser(param.getEmployeeId());
            eslService.updateById(eslEntity);
        }

        final SeatApplicationEntity seatApplicationEntity = SeatApplicationEntity.convertFor(param);
        eslContentService.refreshSeatPlate(seatApplicationEntity, newSeatEslEntity);

        return R.ok();
    }

    /**
     * 删除
     */
    @RequestMapping("/delete")
    @Transactional
    public R delete(@RequestBody Map<String, String> map) {
        //todo unbind AP，需判断该AP所有绑定会议室或工位都删除了，才解绑
        //        for (Long id : ids) {
        //            SeatEntity seatEntity = seatService.getById(id);
        //            if (StringUtils.isNotBlank(seatEntity.getCompId())){
        //                Boolean bindResult = eslWorkingService.unBindAp(seatEntity.getCompId(), seatEntity.getApMac());
        //                if (!bindResult) {
        //                    return R.error("解绑基站失败，请联系管理员");
        //                }
        //            }
        //        }

        String seatCode = map.get("seatCode");
        String compId = map.get("compId");


        SeatVo seatVo = seatService.queryByCodeAndCompId(seatCode, compId);
        if (seatVo == null || seatVo.getId() == null) {
            throw new RRException("无此数据");
        }

        //删除工位价签
        SeatEslEntity seatEslEntity = seatEslService.queryBySeatId(seatVo.getId());
        if (seatEslEntity != null || seatEslEntity.getId() != null) {
            //清空价签所属公司
            EslEntity eslEntity = eslService.queryByEslId(seatEslEntity.getEslId());
            eslEntity.setUser("default");
            eslService.saveOrUpdate(eslEntity);

            seatEslService.removeById(seatEslEntity.getId());
        }

        //删除预约记录
        List<SeatApplicationEntity> seatApplicationList = seatApplicationService.queryBySeatId(seatVo.getId());
        if (CollectionUtil.isNotEmpty(seatApplicationList)) {
            List<SeatApplicationEntity> unfinishList = seatApplicationList.stream().filter(t -> t.getState().equals(Constant.ApplicationState.APPLIED.getValue()) || t.getState().equals(Constant.ApplicationState.STARTED.getValue())).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(unfinishList)) {
                //todo 只有共享工位不允许删除，固定可以，暂时注释掉
                //                throw new RRException("存在已预约或已开始的记录，不允许删除");
            }

            List<Long> ids = seatApplicationList.stream().map(SeatApplicationEntity::getId).collect(Collectors.toList());

            seatApplicationService.removeByIds(ids);
        }
        seatService.removeById(seatVo.getId());

        return R.ok();
    }

    @RequestMapping("/bindStatus")
    public R bindStatus(@Valid @RequestBody SeatBindStatus seatBindStatus) {
        log.debug("seatBindStatus param: {}", seatBindStatus);

        final String seatCode = seatBindStatus.getSeatCode();
        final String corpId = seatBindStatus.getCompId();

        SeatVo existedSeatEntity = seatService.queryByCodeAndCompId(seatCode, corpId);
        if (null == existedSeatEntity) {
            return R.error("工位不存在").put("bindStatus", false);
        }

        final String userId = existedSeatEntity.getUserId();
        boolean hasBind = StringUtils.isNotBlank(userId) && StringUtils.equalsIgnoreCase(userId, seatBindStatus.getUserId());

        if (hasBind) {
            return R.ok().put("bindStatus", true);
        } else {
            return R.ok().put("bindStatus", false);
        }
    }

    @RequestMapping("/bind")
    public R bind(@Valid @RequestBody SeatBindStatus seatBindStatus) {
        log.debug("seat bind param: {}", seatBindStatus);

        final String seatCode = seatBindStatus.getSeatCode();
        final String corpId = seatBindStatus.getCompId();

        SeatVo existedSeatEntity = seatService.queryByCodeAndCompId(seatCode, corpId);
        if (null == existedSeatEntity) {
            return R.error("工位不存在");
        }

        final String seatBoundUserId = existedSeatEntity.getUserId();
        boolean notBindYet = StringUtils.isBlank(seatBoundUserId);

        if (notBindYet) {
            SeatEntity seatEntity = new SeatEntity();
            seatEntity.setId(existedSeatEntity.getId());
            seatEntity.setUserId(seatBindStatus.getUserId());
            seatEntity.setUpdateTime(new Date());

            seatService.updateById(seatEntity);

            return R.ok("绑定成功");
        } else {
            // todo 管理员绑定？

            return R.error("该工位已经绑定了用户id为[" + seatBoundUserId + "]的员工");
        }
    }


}
